From: Giovanni Campagna Date: Sat, 15 Dec 2012 01:41:03 +0000 (+0100) Subject: Add a radial background shade for modal dialogs X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~1013^2^2~2901 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=7e9ecf4eb2ace6668be5aa53d17597fa859d9f62;p=gnome-shell.git Add a radial background shade for modal dialogs Use a new ShellGLSLQuad actor class to build a RadialEffect that can be enabled on Lightboxes to achieve a radial effect similar to the overview one. Then enable it for modal dialogs. https://bugzilla.gnome.org/show_bug.cgi?id=669798 --- diff --git a/js/ui/lightbox.js b/js/ui/lightbox.js index 48a3c8e10..e8d391f95 100644 --- a/js/ui/lightbox.js +++ b/js/ui/lightbox.js @@ -5,12 +5,38 @@ const Lang = imports.lang; const Meta = imports.gi.Meta; const Signals = imports.signals; const St = imports.gi.St; +const Shell = imports.gi.Shell; const Params = imports.misc.params; const Tweener = imports.ui.tweener; const DEFAULT_FADE_FACTOR = 0.4; +const GLSL_DIM_EFFECT_DECLARATIONS = '\ +float compute_dim_factor (const vec2 coords) {\ + vec2 dist = coords - vec2(0.5, 0.5); \ + float elipse_radius = 0.5; \ + /* interpolate darkening value, based on distance from screen center */ \ + float val = min(length(dist), elipse_radius); \ + return mix(0.3, 1.0, val / elipse_radius) * 0.4; \ +}'; +const GLSL_DIM_EFFECT_CODE = '\ + float a = compute_dim_factor (cogl_tex_coord0_in.xy);\ + cogl_color_out = vec4(0, 0, 0, cogl_color_in.a * a);' +; + +const RadialShaderQuad = new Lang.Class({ + Name: 'RadialShaderQuad', + Extends: Shell.GLSLQuad, + + vfunc_build_pipeline: function() { + this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, + GLSL_DIM_EFFECT_DECLARATIONS, + GLSL_DIM_EFFECT_CODE, + true); + }, +}); + /** * Lightbox: * @container: parent Clutter.Container @@ -43,15 +69,21 @@ const Lightbox = new Lang.Class({ width: null, height: null, fadeFactor: DEFAULT_FADE_FACTOR, + radialEffect: false, }); this._container = container; this._children = container.get_children(); this._fadeFactor = params.fadeFactor; - this.actor = new St.Bin({ x: 0, - y: 0, - style_class: 'lightbox', - reactive: params.inhibitEvents }); + if (params.radialEffect) + this.actor = new RadialShaderQuad({ x: 0, + y: 0, + reactive: params.inhibitEvents }); + else + this.actor = new St.Bin({ x: 0, + y: 0, + style_class: 'lightbox', + reactive: params.inhibitEvents }); container.add_actor(this.actor); this.actor.raise_top(); diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index 4e444f113..366e42530 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -89,7 +89,8 @@ const ModalDialog = new Lang.Class({ if (!this._shellReactive) { this._lightbox = new Lightbox.Lightbox(this._group, - { inhibitEvents: true }); + { inhibitEvents: true, + radialEffect: true }); this._lightbox.highlight(this._backgroundBin); this._eventBlocker = new Clutter.Actor({ reactive: true }); diff --git a/src/Makefile.am b/src/Makefile.am index f240343b0..59c9d8f23 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -92,6 +92,7 @@ shell_public_headers_h = \ shell-app-usage.h \ shell-embedded-window.h \ shell-generic-container.h \ + shell-glsl-quad.h \ shell-gtk-embed.h \ shell-global.h \ shell-invert-lightness-effect.h \ @@ -128,6 +129,7 @@ libgnome_shell_base_la_SOURCES = \ shell-embedded-window-private.h \ shell-embedded-window.c \ shell-generic-container.c \ + shell-glsl-quad.c \ shell-invert-lightness-effect.c \ shell-keyring-prompt.h \ shell-keyring-prompt.c \ diff --git a/src/shell-glsl-quad.c b/src/shell-glsl-quad.c new file mode 100644 index 000000000..5e3ce1835 --- /dev/null +++ b/src/shell-glsl-quad.c @@ -0,0 +1,166 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/** + * SECTION:shell-glsl-quad + * @short_description: Draw a rectangle using GLSL + * + * A #ShellGLSLQuad draws one single rectangle, sized to the allocation + * box, but allows running custom GLSL to the vertex and fragment + * stages of the graphic pipeline. + * + * To ease writing the shader, a single texture layer is also used. + */ + +#include "config.h" + +#define CLUTTER_ENABLE_EXPERIMENTAL_API +#define COGL_ENABLE_EXPERIMENTAL_API + +#include +#include "shell-glsl-quad.h" + +G_DEFINE_TYPE (ShellGLSLQuad, shell_glsl_quad, CLUTTER_TYPE_ACTOR); + +struct _ShellGLSLQuadPrivate +{ + CoglPipeline *pipeline; + CoglTexture2D *texture; +}; + +static void +shell_glsl_quad_paint (ClutterActor *actor) +{ + ShellGLSLQuad *self = SHELL_GLSL_QUAD (actor); + ShellGLSLQuadPrivate *priv; + guint8 paint_opacity; + ClutterActorBox box; + + priv = self->priv; + + paint_opacity = clutter_actor_get_paint_opacity (actor); + clutter_actor_get_allocation_box (actor, &box); + + /* semi-transparent black */ + cogl_pipeline_set_color4ub (priv->pipeline, + 0, 0, 0, + paint_opacity); + cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (), + priv->pipeline, + box.x1, box.y1, + box.x2, box.y2); +} + + +/** + * shell_glsl_quad_add_glsl_snippet: + * @quad: a #ShellGLSLQuad + * @hook: where to insert the code + * @declarations: GLSL declarations + * @code: GLSL code + * @is_replace: wheter Cogl code should be replaced by the custom shader + * + * Adds a GLSL snippet to the pipeline used for drawing the actor texture. + * See #CoglSnippet for details. + * + * This is only valid inside the a call to the build_pipeline() virtual + * function. + */ +void +shell_glsl_quad_add_glsl_snippet (ShellGLSLQuad *quad, + ShellSnippetHook hook, + const char *declarations, + const char *code, + gboolean is_replace) +{ + ShellGLSLQuadClass *klass = SHELL_GLSL_QUAD_GET_CLASS (quad); + CoglSnippet *snippet; + + g_return_if_fail (klass->base_pipeline != NULL); + + if (is_replace) + { + snippet = cogl_snippet_new (hook, declarations, NULL); + cogl_snippet_set_replace (snippet, code); + } + else + { + snippet = cogl_snippet_new (hook, declarations, code); + } + + if (hook == SHELL_SNIPPET_HOOK_VERTEX || + hook == SHELL_SNIPPET_HOOK_FRAGMENT) + cogl_pipeline_add_snippet (klass->base_pipeline, snippet); + else + cogl_pipeline_add_layer_snippet (klass->base_pipeline, 0, snippet); + + cogl_object_unref (snippet); +} + +static void +shell_glsl_quad_dispose (GObject *gobject) +{ + ShellGLSLQuad *self = SHELL_GLSL_QUAD (gobject); + ShellGLSLQuadPrivate *priv; + + priv = self->priv; + + g_clear_pointer (&priv->pipeline, cogl_object_unref); + g_clear_pointer (&priv->texture, cogl_object_unref); + + G_OBJECT_CLASS (shell_glsl_quad_parent_class)->dispose (gobject); +} + +static void +shell_glsl_quad_init (ShellGLSLQuad *quad) +{ + quad->priv = G_TYPE_INSTANCE_GET_PRIVATE (quad, SHELL_TYPE_GLSL_QUAD, ShellGLSLQuadPrivate); +} + +static void +shell_glsl_quad_constructed (GObject *object) +{ + ShellGLSLQuad *self; + ShellGLSLQuadClass *klass; + CoglContext *ctx = + clutter_backend_get_cogl_context (clutter_get_default_backend ()); + static const uint8_t tex_data[] = { 0, 0, 0, 0 }; + + G_OBJECT_CLASS (shell_glsl_quad_parent_class)->constructed (object); + + /* Note that, differently from ClutterBlurEffect, we are calling + this inside constructed, not init, so klass points to the most-derived + GTypeClass, not ShellGLSLQuadClass. + */ + klass = SHELL_GLSL_QUAD_GET_CLASS (object); + self = SHELL_GLSL_QUAD (object); + + if (G_UNLIKELY (klass->base_pipeline == NULL)) + { + klass->base_pipeline = cogl_pipeline_new (ctx); + + if (klass->build_pipeline != NULL) + klass->build_pipeline (self); + } + + self->priv->pipeline = cogl_pipeline_copy (klass->base_pipeline); + + self->priv->texture = cogl_texture_2d_new_from_data (ctx, 1, 1, + COGL_PIXEL_FORMAT_RGBA_8888, + 0, tex_data, NULL); + cogl_pipeline_set_layer_texture (self->priv->pipeline, 0, + COGL_TEXTURE (self->priv->texture)); +} + +static void +shell_glsl_quad_class_init (ShellGLSLQuadClass *klass) +{ + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructed = shell_glsl_quad_constructed; + gobject_class->dispose = shell_glsl_quad_dispose; + + actor_class->paint = shell_glsl_quad_paint; + + g_type_class_add_private (klass, sizeof (ShellGLSLQuadPrivate)); +} diff --git a/src/shell-glsl-quad.h b/src/shell-glsl-quad.h new file mode 100644 index 000000000..04a93629d --- /dev/null +++ b/src/shell-glsl-quad.h @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +#ifndef __SHELL_GLSL_QUAD_H__ +#define __SHELL_GLSL_QUAD_H__ + +#include "st.h" +#include + +/** + * ShellSnippetHook: + * Temporary hack to work around Cogl not exporting CoglSnippetHook in + * the 1.0 API. Don't use. + */ +typedef enum { + /* Per pipeline vertex hooks */ + SHELL_SNIPPET_HOOK_VERTEX = 0, + SHELL_SNIPPET_HOOK_VERTEX_TRANSFORM, + + /* Per pipeline fragment hooks */ + SHELL_SNIPPET_HOOK_FRAGMENT = 2048, + + /* Per layer vertex hooks */ + SHELL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM = 4096, + + /* Per layer fragment hooks */ + SHELL_SNIPPET_HOOK_LAYER_FRAGMENT = 6144, + SHELL_SNIPPET_HOOK_TEXTURE_LOOKUP +} ShellSnippetHook; + +#define SHELL_TYPE_GLSL_QUAD (shell_glsl_quad_get_type ()) +#define SHELL_GLSL_QUAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_GLSL_QUAD, ShellGLSLQuad)) +#define SHELL_GLSL_QUAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GLSL_QUAD, ShellGLSLQuadClass)) +#define SHELL_IS_GLSL_QUAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_GLSL_QUAD)) +#define SHELL_IS_GLSL_QUAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GLSL_QUAD)) +#define SHELL_GLSL_QUAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GLSL_QUAD, ShellGLSLQuadClass)) + +typedef struct _ShellGLSLQuad ShellGLSLQuad; +typedef struct _ShellGLSLQuadClass ShellGLSLQuadClass; +typedef struct _ShellGLSLQuadPrivate ShellGLSLQuadPrivate; + +struct _ShellGLSLQuad +{ + ClutterActor parent; + + ShellGLSLQuadPrivate *priv; +}; + +struct _ShellGLSLQuadClass +{ + ClutterActorClass parent_class; + + CoglPipeline *base_pipeline; + + void (*build_pipeline) (ShellGLSLQuad *effect); +}; + +GType shell_glsl_quad_get_type (void) G_GNUC_CONST; + +void shell_glsl_quad_add_glsl_snippet (ShellGLSLQuad *quad, + ShellSnippetHook hook, + const char *declarations, + const char *code, + gboolean is_replace); + +#endif /* __SHELL_GLSL_QUAD_H__ */